package com.month.train.business.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson2.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.month.train.business.domain.*;
import com.month.train.business.dto.ConfirmOrderMQDto;
import com.month.train.business.enums.ConfirmOrderStatusEnum;
import com.month.train.business.enums.RedisKeyPreEnum;
import com.month.train.business.enums.SeatColEnum;
import com.month.train.business.enums.SeatTypeEnum;
import com.month.train.business.mapper.ConfirmOrderMapper;
import com.month.train.business.req.ConfirmOrderDoReq;
import com.month.train.business.req.ConfirmOrderQueryReq;
import com.month.train.business.req.ConfirmOrderTicketReq;
import com.month.train.business.resp.ConfirmOrderQueryResp;
import com.month.train.common.exception.BusinessException;
import com.month.train.common.exception.BusinessExceptionEnum;
import com.month.train.common.resp.PageResp;
import com.month.train.common.util.SnowUtil;
import jakarta.annotation.Resource;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class ConfirmOrderService {

    private static final Logger LOG = LoggerFactory.getLogger(ConfirmOrderService.class);
    @Resource
    private ConfirmOrderMapper confirmOrderMapper;

    @Resource
    private DailyTrainTicketService dailyTrainTicketService;

    @Resource
    private DailyTrainCarriageService dailyTrainCarriageService;

    @Resource
    private DailyTrainSeatService dailyTrainSeatService;

    @Resource
    private AfterConfirmOrderService afterConfirmOrderService;

//    @Autowired
//    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private SkTokenService skTokenService;

    public void save(ConfirmOrderDoReq req) {
        DateTime now = DateTime.now();
        ConfirmOrder confirmOrder = BeanUtil.copyProperties(req, ConfirmOrder.class);
        if (ObjectUtil.isNull(confirmOrder.getId())) {
            confirmOrder.setId(SnowUtil.getSnowflakeNextId());
            confirmOrder.setCreateTime(now);
            confirmOrder.setUpdateTime(now);
            confirmOrderMapper.insert(confirmOrder);
        } else {
            confirmOrder.setUpdateTime(now);
            confirmOrderMapper.updateByPrimaryKey(confirmOrder);
        }
    }

    // 查询列表
    public PageResp<ConfirmOrderQueryResp> queryList(ConfirmOrderQueryReq req) {
        ConfirmOrderExample confirmOrderExample = new ConfirmOrderExample();
        confirmOrderExample.setOrderByClause("id desc");
        ConfirmOrderExample.Criteria criteria = confirmOrderExample.createCriteria();

        LOG.info("查询页码：{}", req.getPage());
        LOG.info("每页条数：{}", req.getPageSize());

        // 分页
        PageHelper.startPage(req.getPage(), req.getPageSize());
        List<ConfirmOrder> confirmOrderList = confirmOrderMapper.selectByExample(confirmOrderExample);

        PageInfo<ConfirmOrder> pageInfo = new PageInfo<>(confirmOrderList);
        LOG.info("总行数：{}", pageInfo.getTotal());
        LOG.info("总页数：{}", pageInfo.getPages());

        List<ConfirmOrderQueryResp> list = BeanUtil.copyToList(confirmOrderList, ConfirmOrderQueryResp.class);
        PageResp<ConfirmOrderQueryResp> PageResp = new PageResp<ConfirmOrderQueryResp>();
        PageResp.setTotal(pageInfo.getTotal());
        PageResp.setList(list);
        return PageResp;
    }

    public void delete(Long id) {
        confirmOrderMapper.deleteByPrimaryKey(id);
    }

    @SentinelResource(value = "doConfirm",blockHandler = "doConfirmBlock")
    public void doConfirm(ConfirmOrderMQDto dto) {

        // 校验令牌数量
//        boolean validSkToken = skTokenService.validSkToken(dto.getDate(), dto.getTrainCode(),LoginMemberContext.getId());
//        if(validSkToken) {
//            LOG.info("令牌校验通过");
//        }else {
//            LOG.info("令牌校验失败");
//            throw new BusinessException(BusinessExceptionEnum.CONFIRM_ORDER_SK_TOKEN_FAIL);
//        }


        // 获取分布式锁
        String lockKey = RedisKeyPreEnum.CONFIRM_ORDER + "-" + DateUtil.formatDate(dto.getDate()) + "-" + dto.getTrainCode();
//        Boolean setIfAbsent = redisTemplate.opsForValue().setIfAbsent(lockKey, lockKey, 60, TimeUnit.SECONDS);
//        if(setIfAbsent) {
//            LOG.info("抢锁成功");
//        }else {
//            LOG.info("抢锁失败");
//            throw new BusinessException(BusinessExceptionEnum.CONFIRM_ORDER_LOCK_FAIL);
//        }

        RLock lock = null;
        /*
        A B C D E
        1.A B
        2. D E
        3.C
        * */
        try {
            // 使用redisson，自带看门狗
            lock = redissonClient.getLock(lockKey);

            // 红锁
//            RedissonRedLock redissonRedLock = new RedissonRedLock(lock, lock, lock);
//            boolean tryLock1 = redissonRedLock.tryLock(0, TimeUnit.SECONDS);

            /**
             waitTime – the maximum time to acquire the lock 等待获取锁时间(最大尝试获得锁的时间)，超时返回false
             leaseTime – lease time 锁时长，即n秒后自动释放锁
             time unit – time unit 时间单位
             */

            // boolean tryLock = lock.tryLock(30, 10, TimeUnit.SECONDS); // 不带看门狗
            boolean tryLock = lock.tryLock(0, TimeUnit.SECONDS); // 带看门狗
            if (!tryLock) {
                LOG.info("很遗憾，没抢到锁，有其他线程在处理改车次订单");
                return;
                // 可以把下面这段放开，只用一个线程来测试，看看redisson的看门狗效果
//                 for (int i = 0; i < 30; i++) {
//                     Long expire = redisTemplate.opsForValue().getOperations().getExpire(lockKey);
//                     LOG.info("锁过期时间还有：{}", expire);
//                     Thread.sleep(1000);
//                 }
            }
            LOG.info("抢锁成功,开始处理订单");
            while(true) {
                // 取确认订单表的记录，同日期车次，状态为I，分页处理，每次取N条
                ConfirmOrderExample confirmOrderExample = new ConfirmOrderExample();
                confirmOrderExample.setOrderByClause("id asc");
                ConfirmOrderExample.Criteria criteria = confirmOrderExample.createCriteria();
                criteria.andDateEqualTo(dto.getDate())
                        .andTrainCodeEqualTo(dto.getTrainCode())
                        .andStatusEqualTo(ConfirmOrderStatusEnum.INIT.getCode());
                PageHelper.startPage(1, 5);
                List<ConfirmOrder> list = confirmOrderMapper.selectByExampleWithBLOBs(confirmOrderExample);
                if(CollUtil.isEmpty(list)) {
                    LOG.info("订单处理完成");
                    break;
                }else {
                    LOG.info("找到{}条待处理的订单，开始处理", list.size());
                }
                // 一条一条的卖
                list.forEach(confirmOrder -> {
                    try{
                        sell(confirmOrder);
                        confirmOrder.setStatus(ConfirmOrderStatusEnum.SUCCESS.getCode());
                    }catch (BusinessException e) {
                        if(e.getE().equals(BusinessExceptionEnum.CONFIRM_ORDER_TICKET_COUNT_ERROR)) {
                            LOG.error("本订单余票不足，继续售卖下一订单");
                            // 处理异常，将订单状态设置为失败
                            confirmOrder.setStatus(ConfirmOrderStatusEnum.EMPTY.getCode());
                            updateStatus(confirmOrder);
                        }else {
                            LOG.error("购票异常", e);
                            throw e;
                        }
                    } finally {
                        updateStatus(confirmOrder);
                    }
                });
            }

//            LOG.info("购票结束,释放锁! lockKey:{}", lockKey);
//            redisTemplate.delete(lockKey);
        } catch (InterruptedException e) {
            LOG.error("购票异常", e);
        } finally {
            LOG.info("购票结束,释放锁!");
            if(null != lock && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 更新状态
     * */

    public void updateStatus(ConfirmOrder confirmOrder) {
        ConfirmOrder confirmOrderForUpdate = new ConfirmOrder();
        confirmOrderForUpdate.setId(confirmOrder.getId());
        confirmOrderForUpdate.setUpdateTime(new Date());
        confirmOrderForUpdate.setStatus(confirmOrder.getStatus());
        confirmOrderMapper.updateByPrimaryKeySelective(confirmOrderForUpdate);

    }

    /**
     * 售票
     * */
    private void sell(ConfirmOrder confirmOrder) {
        // 增加排队效果
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        ConfirmOrderDoReq req = new ConfirmOrderDoReq();
        req.setMemberId(confirmOrder.getMemberId());
        req.setDate(confirmOrder.getDate());
        req.setTrainCode(confirmOrder.getTrainCode());
        req.setStart(confirmOrder.getStart());
        req.setEnd(confirmOrder.getEnd());
        req.setDailyTrainTicketId(confirmOrder.getDailyTrainTicketId());
        req.setTickets(JSON.parseArray(confirmOrder.getTickets(), ConfirmOrderTicketReq.class));
        req.setImageCode("");
        req.setImageCodeToken("");
        req.setLogId("");
        // 省略业务数据校验，如：车次是否存在，余票是否存在，车次是否在有有效期，ticket>0,同车次的乘客是否买过
        // 将订单设置为处理中，防止重复处理
        LOG.info("将订单设置为处理中，防止重复处理,confirm_order.id:{}", confirmOrder.getId());
        confirmOrder.setStatus(ConfirmOrderStatusEnum.PENDING.getCode());
        updateStatus(confirmOrder);

        Date date = req.getDate();
        String trainCode = req.getTrainCode();
        String start = req.getStart();
        String end = req.getEnd();
        List<ConfirmOrderTicketReq> tickets = req.getTickets();

        // 保存确认订单表，状态初始
//            DateTime now = DateTime.now();
//            ConfirmOrder confirmOrder = new ConfirmOrder();
//            confirmOrder.setId(SnowUtil.getSnowflakeNextId());
//            confirmOrder.setCreateTime(now);
//            confirmOrder.setUpdateTime(now);
//            confirmOrder.setMemberId(req.getMemberId());
//            confirmOrder.setDate(date);
//            confirmOrder.setTrainCode(trainCode);
//            confirmOrder.setStart(start);
//            confirmOrder.setEnd(end);
//            confirmOrder.setDailyTrainTicketId(req.getDailyTrainTicketId());
//            confirmOrder.setStatus(ConfirmOrderStatusEnum.INIT.getCode());
//            confirmOrder.setTickets(JSON.toJSONString(req.getTickets()));
//            confirmOrderMapper.insert(confirmOrder);


        // 从数据库查出订单
//        ConfirmOrderExample confirmOrderExample = new ConfirmOrderExample();
//        confirmOrderExample.setOrderByClause("id asc");
//        ConfirmOrderExample.Criteria criteria = confirmOrderExample.createCriteria();
//        criteria.andDateEqualTo(req.getDate())
//                .andTrainCodeEqualTo(req.getTrainCode())
//                .andMemberIdEqualTo(req.getMemberId())
//                .andStatusEqualTo(ConfirmOrderStatusEnum.INIT.getCode());
//
//        List<ConfirmOrder> list = confirmOrderMapper.selectByExampleWithBLOBs(confirmOrderExample);
//        ConfirmOrder confirmOrder;
//        if(CollUtil.isEmpty(list)) {
//            LOG.info("没有找到订单，结束");
//            return;
//        }else {
//            LOG.info("找到{}条订单，开始处理", list.size());
//            confirmOrder = list.get(0);
//        }

        // 查出余票记录，得到真实的库存
        DailyTrainTicket dailyTrainTicket = dailyTrainTicketService.selectByUnique(date, trainCode, start, end);
        LOG.info("余票信息：{}", dailyTrainTicket);

        // 扣减余票数量，判断余票是否足够
        reduceTickets(req, dailyTrainTicket);
        // 最终选座结果
        List<DailyTrainSeat> finalSeatList = new ArrayList<>();

        // 计算相对第一个座位的偏移值
        // 比如选择C1,D2,偏移值[0,5]
        // 选择A1,B1,C1,偏移值[0,1,2]
        // 判断是否有选座
        ConfirmOrderTicketReq ticketReq0 = tickets.get(0);
        if (StrUtil.isNotBlank(ticketReq0.getSeat())) {
            LOG.info("本次购票有选座");
            // 查出本次选座的座位类型有那些列，用于计算所选座位与第一座位的偏移值
            List<SeatColEnum> colEnumList = SeatColEnum.getColsByType(ticketReq0.getSeatTypeCode());
            LOG.info("本次选座的座位类型包含的列：{}", colEnumList);

            // 组成和前端两排选座一样的列表，用于作参照的座位列表
            List<String> referSeatList = new ArrayList<>();
            for (int i = 1; i <= 2; i++) {
                for (SeatColEnum seatColEnum : colEnumList) {
                    referSeatList.add(seatColEnum.getCode() + i);
                }
            }
            LOG.info("用于作参照的座位：{}", referSeatList);
            List<Integer> offsetList = new ArrayList<>();
            // 计算所选座位与第一座位的偏移值
            List<Integer> aboluteOffsetList = new ArrayList<>();
            for (ConfirmOrderTicketReq ticketReq : tickets) {
                int index = referSeatList.indexOf(ticketReq.getSeat());
                aboluteOffsetList.add(index);
            }
            LOG.info("所有座位的绝对偏移值：{}", aboluteOffsetList);
            for (Integer index : aboluteOffsetList) {
                int offset = index - aboluteOffsetList.get(0);
                offsetList.add(offset);
            }
            LOG.info("所有座位的相对第一个位置的偏移值：{}", offsetList);

            getSeat(finalSeatList,
                    date, trainCode, ticketReq0.getSeatTypeCode(),
                    ticketReq0.getSeat().split("")[0], offsetList,
                    dailyTrainTicket.getStartIndex(), dailyTrainTicket.getEndIndex());

        } else {
            LOG.info("本次购票无选座");
            for (ConfirmOrderTicketReq ticketReq : tickets) {
                getSeat(finalSeatList,
                        date, trainCode, ticketReq.getSeatTypeCode(),
                        null, null,
                        dailyTrainTicket.getStartIndex(), dailyTrainTicket.getEndIndex());
            }
        }

        LOG.info("最终选座：{}", finalSeatList);

        // 选中座位后事务处理

        // 座位表修改售卖情况
        // 余票详情表修改余票
        // 会员增加购票记录
        // 更新确认订单为成功
        try {
            afterConfirmOrderService.afterDoConfirm(dailyTrainTicket, finalSeatList, tickets, confirmOrder);
        } catch (Exception e) {
            LOG.error("保存购票信息失败", e);
            throw new BusinessException(BusinessExceptionEnum.CONFIRM_ORDER_EXCEPTION);
        }
    }

    private void getSeat(List<DailyTrainSeat> finalSeatList,
                         Date date, String trainCode, String seatType,
                         String column,List<Integer> offsetList,Integer startIndex,
                         Integer endIndex) {
        List<DailyTrainSeat> getSeatList = new ArrayList<>();
        List<DailyTrainCarriage> carriageList = dailyTrainCarriageService.selectBySeatType(date, trainCode, seatType);
        LOG.info("共查出{}个符合条件的车厢", carriageList.size());

        // 一个车厢一个车厢的获取座位数据
        for(DailyTrainCarriage dailyTrainCarriage : carriageList) {
            // 挑选符合条件的座位
            LOG.info("开始从车厢{}选座",dailyTrainCarriage.getIndex());
            getSeatList = new ArrayList<>();    // 换车厢，清空
            List<DailyTrainSeat> seatList = dailyTrainSeatService.selectByCarriage(date, trainCode, dailyTrainCarriage.getIndex());
            LOG.info("车厢{}的座位数：{}",dailyTrainCarriage.getIndex(),seatList.size());
            for (int i = 0;i < seatList.size(); i++) {
                DailyTrainSeat dailyTrainSeat = seatList.get(i);

                String col = dailyTrainSeat.getCol();
                Integer seatIndex = dailyTrainSeat.getCarriageSeatIndex();

                // 判断当前座位不能被选中过
                boolean alreadyChooseFlag = false;
                for (DailyTrainSeat finalSeat : finalSeatList) {
                    if(finalSeat.getId().equals(dailyTrainSeat.getId())) {
                        alreadyChooseFlag = true;
                        break;
                    }
                }
                if(alreadyChooseFlag) {
                    LOG.info("座位{}已被选中过，继续判断下一个座位",seatIndex);
                    continue;
                }

                // 判断column,有值的话要比对列号
                if(StrUtil.isBlank(column)) {
                    LOG.info("无选座");
                }else {
                    if(!column.equals(col)) {
                        LOG.info("座位{}列值不对，继续判断下一个座位,当前的列{}，目标列{}",
                                seatIndex,col,column);
                        continue;
                    }
                }

                boolean isChoose = calSell(dailyTrainSeat,startIndex,endIndex);
                if(isChoose) {
                    getSeatList.add(dailyTrainSeat);
                    LOG.info("选中座位");
                }else {
                    continue;
                }

                // 根据offset选剩下的座位
                boolean isGetAllOffsetSeat = true;
                if(CollUtil.isNotEmpty(offsetList)) {
                    LOG.info("有偏移值{}，校验偏移的座位是否可选",offsetList);
                    // 从索引1开始，索引0是当前已选择的票
                    for (int j = 1; j < offsetList.size(); j++) {
                        Integer offset = offsetList.get(j);
                        // 座位在库的索引是从1开始
                        // int nextIndex = seatIndex + offset - 1;
                        int nextIndex = i + offset;

                        // 有选座时，一定在同一个车厢
                        if(nextIndex >= seatList.size()) {
                            LOG.info("座位{}超出了车厢{}的座位数，继续判断下一个座位",
                                    nextIndex,dailyTrainCarriage.getIndex());
                            isGetAllOffsetSeat = false;
                            break;
                        }

                        DailyTrainSeat nextDailyTrainSeat = seatList.get(nextIndex);
                        boolean isChooseNext = calSell(nextDailyTrainSeat,startIndex,endIndex);
                        if(isChooseNext) {
                            LOG.info("座位{}被选中",nextDailyTrainSeat.getCarriageSeatIndex());
                            getSeatList.add(nextDailyTrainSeat);
                        }else {
                            LOG.info("座位{}不可选",nextDailyTrainSeat.getCarriageSeatIndex());
                            isGetAllOffsetSeat = false;
                            break;
                        }
                    }
                }
                if(!isGetAllOffsetSeat) {
                    getSeatList = new ArrayList<>();    // 清空
                    continue;
                }

                // 保存选好的座位
                finalSeatList.addAll(getSeatList);
                return;
            }
        }
    }

    /**
     * 计算某座位在区间是否可卖
     * */
    private boolean calSell(DailyTrainSeat dailyTrainSeat,Integer startIndex,
                         Integer endIndex) {
        String sell = dailyTrainSeat.getSell();
        String sellPart = sell.substring(startIndex, endIndex);
        if(Integer.parseInt(sellPart) > 0) {
            LOG.info("座位{}在本车站区间{}--{}已售过票，不可选中该座位",dailyTrainSeat.getCarriageSeatIndex(),
                    startIndex,endIndex);
            return false;
        }else {
            LOG.info("座位{}在本车站区间{}--{}未售过票，可选中该座位",dailyTrainSeat.getCarriageSeatIndex(),
                    startIndex,endIndex);
            // 111
            String curSell = sellPart.replace('0', '1');
            // 0111
            curSell = StrUtil.fillBefore(curSell,'0', endIndex);
            curSell = StrUtil.fillAfter(curSell,'0',sell.length());

            // 当前区间售票信息curSell与库里的已售信息sell按位与，即可得到该座位卖出此票后的售票详情
            // 32
            int newSellInt = NumberUtil.binaryToInt(curSell) | NumberUtil.binaryToInt(sell);
            // 11111
            String newSell = NumberUtil.getBinaryStr(newSellInt);
            newSell = StrUtil.fillBefore(newSell,'0',sell.length());
            LOG.info("座位{}在本车站区间{}--{}卖出该票后，最终售票详情：{}",dailyTrainSeat.getCarriageSeatIndex(),
                    startIndex,endIndex,newSell);
            dailyTrainSeat.setSell(newSell);
            return true;
        }
    }

    private static void reduceTickets(ConfirmOrderDoReq req, DailyTrainTicket dailyTrainTicket) {
        LOG.info("开始扣减余票");
        for (ConfirmOrderTicketReq ticketReq : req.getTickets()) {
            String seatTypeCode = ticketReq.getSeatTypeCode();
            SeatTypeEnum seatTypeEnum = EnumUtil.getBy(SeatTypeEnum::getCode, seatTypeCode);
            switch (seatTypeEnum) {
                case YDZ -> {
                    int countLeft = dailyTrainTicket.getYdz() - 1;
                    if(countLeft < 0) {
                        throw new BusinessException(BusinessExceptionEnum.CONFIRM_ORDER_TICKET_COUNT_ERROR);
                    }
                    dailyTrainTicket.setYdz(countLeft);
                }
                case EDZ -> {
                    int countLeft = dailyTrainTicket.getEdz() - 1;
                    if(countLeft < 0) {
                        throw new BusinessException(BusinessExceptionEnum.CONFIRM_ORDER_TICKET_COUNT_ERROR);
                    }
                    dailyTrainTicket.setEdz(countLeft);
                }
                case RW -> {
                    int countLeft = dailyTrainTicket.getRw() - 1;
                    if(countLeft < 0) {
                        throw new BusinessException(BusinessExceptionEnum.CONFIRM_ORDER_TICKET_COUNT_ERROR);
                    }
                    dailyTrainTicket.setRw(countLeft);
                }
                case YW -> {
                    int countLeft = dailyTrainTicket.getYw() - 1;
                    if(countLeft < 0) {
                        throw new BusinessException(BusinessExceptionEnum.CONFIRM_ORDER_TICKET_COUNT_ERROR);
                    }
                    dailyTrainTicket.setYw(countLeft);
                }
            }
        }
    }

    /**
     * 查询前面有几个人在排队
     */
    public Integer queryLineCount(Long id) {
        ConfirmOrder confirmOrder = confirmOrderMapper.selectByPrimaryKey(id);
        ConfirmOrderStatusEnum statusEnum = EnumUtil.getBy(ConfirmOrderStatusEnum::getCode, confirmOrder.getStatus());
        int result = switch (statusEnum) {
            case PENDING -> 0; // 排队0
            case SUCCESS -> -1; // 成功
            case FAILURE -> -2; // 失败
            case EMPTY -> -3; // 无票
            case CANCEL -> -4; // 取消
            case INIT -> 999; // 需要查表得到实际排队数量
        };

        if (result == 999) {
            // 排在第几位，下面的写法：where a=1 and (b=1 or c=1) 等价于 where (a=1 and b=1) or (a=1 and c=1)
            ConfirmOrderExample confirmOrderExample = new ConfirmOrderExample();
            confirmOrderExample.or().andDateEqualTo(confirmOrder.getDate())
                    .andTrainCodeEqualTo(confirmOrder.getTrainCode())
                    .andCreateTimeLessThan(confirmOrder.getCreateTime())
                    .andStatusEqualTo(ConfirmOrderStatusEnum.INIT.getCode());
            confirmOrderExample.or().andDateEqualTo(confirmOrder.getDate())
                    .andTrainCodeEqualTo(confirmOrder.getTrainCode())
                    .andCreateTimeLessThan(confirmOrder.getCreateTime())
                    .andStatusEqualTo(ConfirmOrderStatusEnum.PENDING.getCode());
            return Math.toIntExact(confirmOrderMapper.countByExample(confirmOrderExample));
        } else {
            return result;
        }
    }


    /*降级方法，需包含限流方法的所有参数和BlockException参数*/
    public void doConfirmBlock(ConfirmOrderDoReq req, BlockException e) {
        LOG.info("购票请求被限流：{}", req);
        throw new BusinessException(BusinessExceptionEnum.CONFIRM_ORDER_FLOW_EXCEPTION);
    }

    /*取消排队*/
    public Integer cancel(Long id) {
        ConfirmOrderExample confirmOrderExample = new ConfirmOrderExample();
        ConfirmOrderExample.Criteria criteria = confirmOrderExample.createCriteria();
        criteria.andIdEqualTo(id).andStatusEqualTo(ConfirmOrderStatusEnum.INIT.getCode());
        ConfirmOrder confirmOrder = new ConfirmOrder();
        confirmOrder.setStatus(ConfirmOrderStatusEnum.CANCEL.getCode());
        return confirmOrderMapper.updateByExampleSelective(confirmOrder,confirmOrderExample);
    }
}
